package middlewares

// by daoyi
import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"simai_oa/controller"
	"simai_oa/model"
	"simai_oa/tool"
	"simai_oa/tool/convert"
	"strconv"
	"strings"
)

// SkipperFunc 定义中间件跳过函数
type SkipperFunc func(*gin.Context) bool

func InitMiddlewares(c *gin.Context) {

	//鉴权：
	AuthCheckRole()(c)

	//jwt中间件 判断用户是否登陆
	JWThMiddleware()(c)

	//
	//apiPrefix := "/admin"
	//var notCheckLoginUrlArr []string
	//
	//// 权限验证
	//var notCheckPermissionUrlArr []string
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, notCheckLoginUrlArr...)
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/menu/menubuttonlist")
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/menu/allmenu")
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/admins/adminsroleidlist")
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/login/info")
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/user/editpwd")
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/role/rolemenuidlist")
	//notCheckPermissionUrlArr = append(notCheckPermissionUrlArr, apiPrefix+"/role/allrole")
	//CasbinMiddleware(AllowPathPrefixSkipper(notCheckPermissionUrlArr...))
}

// JWThMiddleware 中间件
func JWThMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI 4.放在请求头中的Authorization里
		// 这里假设Token放在Header的token中
		token := strings.Split(c.Request.Header["Authorization"][0], " ")[1] //放在请求头中的Authorization里
		//token := c.Request.Header.Get("token") //1.放在请求头
		//token := c.Query("token") //2.放在url中
		if token == "" {
			// 处理 没有token的时候
			c.Abort() // 不会继续停止
			c.JSON(http.StatusOK, gin.H{
				"code": 12306,
				"msg":  "token验证错误,您无权访问！",
			})
			return
		}
		// 解析
		mc, err := tool.ParseToken(token)
		if err != nil {
			// 处理 解析失败
			c.Abort()
			c.JSON(http.StatusOK, gin.H{
				"code": 12306,
				"msg":  "token解析验证错误,您无权访问！",
			})
			return
		}
		// 将当前请求的Id信息保存到请求的上下文c上
		c.Set("Id", mc.Id)
		c.Next()
	}
}

// JWThMiddleware 中间件
func JWThMiddlewareApi() func(c *gin.Context) {
	return func(c *gin.Context) {
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI 4.放在请求头中的Authorization里
		// 这里假设Token放在Header的token中
		token := strings.Split(c.Request.Header["Authorization"][0], " ")[1] //放在请求头中的Authorization里
		// token := c.Request.Header.Get("token")
		// token := c.Query("token")
		if token == "" {
			// 处理 没有token的时候
			tokenp := c.PostForm("token")
			if tokenp == "" {
				c.Abort() // 不会继续停止
				c.JSON(http.StatusOK, gin.H{
					"code": 12306,
					"msg":  "token验证错误,您无权访问！",
				})
				return
			}
			token = tokenp
		}
		// 解析
		mc, err := tool.ParseApiToken(token)
		if err != nil {
			// 处理 解析失败
			c.Abort()
			c.JSON(http.StatusOK, gin.H{
				"code": 12306,
				"msg":  "token解析验证错误,您无权访问！",
			})
			return
		}
		// 将当前请求的Id信息保存到请求的上下文c上
		c.Set("Id", mc.Id)
		c.Next()
	}
}

// CasbinMiddleware casbin中间件
func CasbinMiddleware(skipper ...SkipperFunc) gin.HandlerFunc {
	return func(c *gin.Context) {
		if len(skipper) > 0 && skipper[0](c) {
			c.Next()
			return
		}
		// 用户ID
		token, _ := tool.GetTokenFromRequest(c)
		uID := tool.GetValueFromTokenClaims("Id", token.Claims)
		userID, _ := strconv.Atoi(uID)
		if convert.ToUint64(userID) == controller.SUPER_ADMIN_ID {
			c.Next()
			return
		}
		p := c.Request.URL.Path
		m := c.Request.Method
		if b, err := model.CsbinCheckPermission(convert.ToString(userID), p, m); err != nil {
			controller.ResFail(c, "err303"+err.Error())
			fmt.Println("err303**", err)
			return
		} else if !b {
			controller.ResFail(c, "没有访问权限")
			return
		}
		c.Next()
	}
}

// 检查角色，鉴权
func AuthCheckRole() func(c *gin.Context) {
	return func(c *gin.Context) {
		// TODO 认证 jwt
		token, _ := tool.GetTokenFromRequest(c)
		name := tool.GetValueFromTokenClaims("Name", token.Claims)
		roleName := tool.GetValueFromTokenClaims("RoleName", token.Claims)
		gameId := tool.GetValueFromTokenClaims("GameId", token.Claims)
		// 鉴权 casbin
		if roleName == "超级管理员" {
			fmt.Printf("用户:%s, 是 %s, 直接通过! \n", name, roleName)
			c.Next()
			return
		}

		// 数据库匹配
		var rmenu []model.RoleMenu
		tool.Gdb.Table("za_role_menu").Where("role_id = ?", gameId).Select("menu_id").Find(&rmenu)
		var count int64
		for i := range rmenu {
			tool.Gdb.Table("za_menu").Where("role_id = ? AND url = ?", gameId, rmenu[i].MenuID).Count(&count)
			if count > 0 {
				break
			}
		}

		if count == 0 {
			fmt.Printf("AuthCheckRole error: %s method:%s path:%s\n", "您本次请求无权限！", c.Request.Method, c.Request.URL.Path)
			c.Abort()
			c.JSON(http.StatusOK, gin.H{
				"code": 500,
				"msg":  "您本次请求无权限！",
			})
			return
		}

		// 匹配成功
		fmt.Printf("username :%s, isTrue: %v, role: %s method: %s path: %s \n", name, "匹配成功", roleName, c.Request.Method, c.Request.URL.Path)
		c.Next()
	}
}
